package siclink;

import java.io.BufferedWriter;
import java.io.FileWriter;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.Set;
import javax.swing.JOptionPane;

public class SicLink {
	public static String baseDirectoryInputMessage = "Please enter in the file location of the input file: \nNote: This will also be the location of the output files.";
	public static String inputFileNameMessage = "Please enter in the input file name:";
	public static String anotherInputFileNameMessage = "Do you have another input file? (Y/N)";
	public static String programAddressMessage = "Enter the starting program address in hexidecimal:";
	public static String programAddressErrorMessage = "Starting Address must be less than 201 hexidecimal. Please reenter.";
	public static String completionMessage = "Your output files are located in this directory: \n";
	private static String baseDirectory = "";
	private static ArrayList<String> testFileNames = new ArrayList<String>();
	private static String anotherInputFile = "Y";
	public static int programAddress = 0x00;
	private static String sourceFileName = null;	
	private static String destinationFileName = "Outfile.txt";	
	public static LinkedHashMap<String, Integer> symbolTable = new LinkedHashMap<String, Integer>();
	public static LinkedHashMap<String, Integer> controlSectionTable = new LinkedHashMap<String, Integer>();
	private static String HEADING_LINE_1 = "Control\tSection\n";
	private static String HEADING_LINE_2 = "Name\tName\tAddress\tLength\n";
	private static String HEADING_LINE_3 = "------------------------------\n";
	private static String MEMORY_HEADING_LINE_1 = "Memory\n";
	private static String MEMORY_HEADING_LINE_2 = "address\t\t\t\t\t  Contents\n";
	private static String MEMORY_HEADING_LINE_3 = "-------\t--------------------------------------------\n";	

	public static void main(String[] args) throws Exception{
		//baseDirectory = "C:\Users\janicka\Documents\Personal Documents\CIS 535\Assignment 5\";
		//testFileName = "Assignment 5 input in one text file";
		//testFileName = "Assignment 5 input - PROGA only";
		//testFileName = "Assignment 5 input - PROGB only";
		//testFileName = "Assignment 5 input - PROGC only";
		baseDirectory = promptUserForInput(baseDirectoryInputMessage);
		programAddress = 0x00;
		while (anotherInputFile.equalsIgnoreCase("Y")){
			String tempInputFileName = promptUserForInput(inputFileNameMessage);
			if (!tempInputFileName.endsWith(".txt")){
				tempInputFileName = tempInputFileName + ".txt";
			}
			testFileNames.add(tempInputFileName);
			anotherInputFile = promptUserForInput(anotherInputFileNameMessage);
		}
		programAddress = Integer.parseInt(promptUserForInput(programAddressMessage), 16);
		if (programAddress > 0x200){
			showErrorMessage(programAddressErrorMessage);
			programAddress = Integer.parseInt(promptUserForInput(programAddressMessage), 16);
		}
		for (String s : testFileNames) {
			sourceFileName =  baseDirectory + s;
			System.out.println(sourceFileName);
			PassOne.processFile(sourceFileName, programAddress);
		}
		for (String s : testFileNames) {
			sourceFileName =  baseDirectory + s;
			PassTwo.processFile(sourceFileName, programAddress);
		}		
		createOutputFile(destinationFileName, printSymbolTable(), printMemoryRegister());
		showMessage(completionMessage, baseDirectory);
	}

	public static String promptUserForInput(String message) throws Exception{
		Object userReponse = JOptionPane.showInputDialog(null, message, "Input",
				JOptionPane.QUESTION_MESSAGE, null, null, null);
		return (String) userReponse;
	}

	public static void showMessage(String message, String location) throws Exception{
		JOptionPane.showMessageDialog(null, message + location, "Completed!",
				JOptionPane.PLAIN_MESSAGE);
	}
	
	private static void showErrorMessage(String message) throws Exception{
		JOptionPane.showMessageDialog(null, message, "Error!",
				JOptionPane.ERROR_MESSAGE);
	}	

	public static StringBuffer printMemoryRegister() {
		int counter = 0;
		int memoryLocation = programAddress;
		StringBuffer buffer = new StringBuffer();
		buffer.append(MEMORY_HEADING_LINE_1);
		buffer.append(MEMORY_HEADING_LINE_2);
		buffer.append(MEMORY_HEADING_LINE_3);		
		buffer.append(pad(Integer.toHexString(memoryLocation).toUpperCase(), 4) + "\t");
		for (int i = 0; i < PassTwo.memoryRegister.length; i++){
			buffer.append(String.valueOf(PassTwo.memoryRegister[i]));
			counter++;
			if (counter > 0 && counter % 8 == 0) {
				buffer.append("    ");
			}
			if (counter > 0 && counter % 32 == 0 && counter < 1024) {
				buffer.append("\n");
				memoryLocation += 0x10;
				buffer.append(pad(Integer.toHexString(memoryLocation).toUpperCase(), 4) + "\t");
			}
		}
		buffer.append("\n\nEXECADDR: " + pad(Integer.toHexString(PassTwo.controlSectionAddress), 4));
		return buffer;
	}

	public static StringBuffer printSymbolTable(){
		StringBuffer buffer = new StringBuffer();
		buffer.append(HEADING_LINE_1);
		buffer.append(HEADING_LINE_2);
		buffer.append(HEADING_LINE_3);
		String tempString = "";
		Set<String> keys = symbolTable.keySet();
		for (Iterator<String> i = keys.iterator(); i.hasNext();) {
			String key = i.next().toString();
			int value = symbolTable.get(key);
			if (controlSectionTable.containsKey(key)){
				tempString = key + "\t" + key + "\t" + pad(Integer.toHexString(value).toUpperCase(), 4) + "\t" + pad(Integer.toHexString(SicLink.controlSectionTable.get(key)).toUpperCase(), 4) + "\n";	
			} else {
				tempString = "\t\t" + key + "\t" + pad(Integer.toHexString(value).toUpperCase(), 4) + "\t\t\n";	
			}
			buffer.append(tempString);		        
		}
		return buffer;
	}

	public static String pad(String str, int length) {
		if (str.length() == 1)
			str = "0" + str;
		for(int i = 0; str.length() < length; i++)
			str = "0" + str;
		return str;
	}
	public static void createOutputFile(String fileName, StringBuffer dataOne, StringBuffer dataTwo) throws IOException{
        BufferedWriter output = new BufferedWriter(new FileWriter(baseDirectory + fileName)); 
        output.write(dataOne.toString());
        output.write("\n");
        output.write(dataTwo.toString());
		output.flush();  
		output.close(); 
	}		
}